import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.ClassPathResource;

import java.lang.reflect.Field;

public class ApplicationContextParser {
    private final GenericApplicationContext context;

    public ApplicationContextParser() {
        this.context = new GenericApplicationContext();
    }

    public void parseApplicationContext() {
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
        reader.loadBeanDefinitions(new ClassPathResource("applicationContext.xml"));
        context.refresh();
    }

    public void performDependencyInjection() {
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) context.getBeanFactory();
        String[] beanNames = context.getBeanDefinitionNames();

        for (String beanName : beanNames) {
            BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);

            if (beanDefinition instanceof RootBeanDefinition) {
                RootBeanDefinition rootBeanDefinition = (RootBeanDefinition) beanDefinition;
                Class<?> beanClass = rootBeanDefinition.getBeanClass();

                if (beanClass != null) {
                    Field[] declaredFields = beanClass.getDeclaredFields();

                    for (Field field : declaredFields) {
                        if (rootBeanDefinition.getPropertyValues().contains(field.getName())) {
                            Object propertyValue = rootBeanDefinition.getPropertyValues().getPropertyValue(field.getName()).getValue();

                            if (propertyValue instanceof RuntimeBeanReference) {
                                String referencedBeanName = ((RuntimeBeanReference) propertyValue).getBeanName();
                                Object referencedBean = context.getBean(referencedBeanName);
                                field.setAccessible(true);

                                try {
                                    field.set(context.getBean(beanName), referencedBean);
                                } catch (IllegalAccessException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    public <T> T getBean(Class<T> beanClass) {
        return context.getBean(beanClass);
    }
}